<?php

	/**
	 * 	Kortfattat hur det funkar
	 * 	1. Preparera SQL-fråga med ? där parametrar ska in. Använd prepare returnerar stmt-objekt
	 * 	2. Bind parametrar med hjälp av stmt-objektet. ->bind_param("s", $param)    "s" == sträng
	 * 	3. Exekvera SQL-frågan med execute-metoden som finns på stmt-objektet
	 * 	4. Hämta resultatet med fetch
	 * 	5. Stäng stmt-objektet
	 * 
	 */ 


	// Inkluderar fil med användarnamn, lösenord, osv.
	include_once 'DBConfig.php';
	
	class DBConnection{
		private $m_mysqli = NULL;
		
		
		/**
		 * Koppla upp sig mot databasen
		 * @return bool true om uppkopplingen lyckas
		 */
		public function Connect(){
			echo "Kopplar upp sig till databas";
			
			$this->m_mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
			$this->m_mysqli->set_charset(DB_CHARSET);
			
			// Returnerar false om fel uppstått vid uppkopplingen
			if($this->m_mysqli->connect_errno){
				echo "Connection failed: $this->m_mysqli->connect_error";
				return FALSE;
			}
			echo "Anslutningen lyckades";
			return TRUE;
		}
		
		// Stänger databasuppkopplingen
		public function Close(){
			echo "Stänger uppkopplingen";
			$this->m_mysqli->close();
			$this->m_mysqli = NULL;
		}
		
		// Funktion som droppar en tabell
		public function DropTable($tableName)
		{
			if ($this->m_mysqli == NULL) {
				throw new Exception("DBConnection, must call Connect before calling Prepare");
			}	
			
			echo "Droppar tabellen";
			$sql = "DROP TABLE  " . $tableName;
			return $this->RunQuery($sql);
		}
		
		/**
		 * Kontrollerar om en tabell existerar
		 * @return bool
		 */
		public function TableExists($tableName){
			if ($this->m_mysqli == NULL) {
				throw new Exception("DBConnection, must call Connect before calling Prepare");
			}	
			
			// Skapar en ny tabell med namnet
			$sql = "SHOW TABLE STATUS LIKE '$tableName'";
			
			$result = $this->m_mysqli->query($sql);
			
			// fetch_assoc returnerar en associatic array med data för varje rad
			$row_array = $result->fetch_assoc();
			
			// Om arrayen har 1 eller fler saker i den betyder det att tabellen finns.
			if (count($row_array > 0)) {
				return TRUE;
			} else {
				return false;
			}
		}
		
		/**
		 * Kör en SQL-query
		 * Delvis öppen för sql-injections om inte man skickat in SQL-frågan med real_escape_string
		 * @return bool TRUE om lyckad fråga.
		 */
		public function RunQuery($sql){
			
			if ($this->m_mysqli == NULL) {
                 throw new Exception("DBConnection, must call Connect before calling Prepare");
         	 }
			if ($this->m_mysqli->query($sql) == FALSE){
				echo "'$sql' misslyckades" . $this->m_mysqli->error;
				return FALSE;
			}
			echo "lol";
			return TRUE;
			
		}
		
		/**
		 * Preparerar en SQL-fråga
		 * @param string $sql en sträng innehållande SQL-frågan med frågetecken (?) vid parametrarna
		 * $return FALSE vid fel eller mysql_stmt
		 */
		public function Prepare($sql){
			if ($this->m_mysqli == NULL) {
            	throw new Exception("DBConnection, must call Connect before calling Prepare");
            }
			
			$stmt = $this->m_mysqli->prepare($sql);
			if ($stmt === FALSE) {
				echo "Preparering av '$sql' misslyckad " . $this->m_mysqli->error;
				return FALSE;
			}
			
			return $stmt;
		} 
		
		/**
		 * Preparerar en SQL-fråga och binder den med parametrar
		 * 
		 * @param string $sqlQueryToPrepare SQL-frågan med frågetecken (?) vid parametrarna som skall bindas
		 * @param string $bindParamTypeString Sträng innehållandes typen för satsen som skall prepareras. "s" = sträng, "ss" = dubbelsträng osv
		 * @param array $parameterArray Array med parametrar som skall bindas till SQL-frågan.
		 * @return FALSE vid fel annars stmt
		 */
		
		public function PrepareWithParams($sqlQueryToPrepare, $bindParamTypeString, $parameterArray){
			$stmt = $this->Prepare($sqlQueryToPrepare);
			
			if ($stmt === FALSE) {
				echo "Preparering av '$sql' misslyckad " . $this->m_mysqli->error;
				return FALSE;
			}
			
			$parameters = array_merge(array($bindParamTypeString), $parameterArray);
			
			if (call_user_func_array(array($stmt, "bind_param"), $parameters) === FALSE) {
				echo "bind_param failed " . $stmt->error;
            	return false;
			}
			
			return $stmt;
		}
		

		/**
		 * Returnerar alla objekt från en tabell
		 * @param string $className Namnet på klassen som representerar tabellraderna
		 * @param string $tableName Namnet på tabelleb
		 * @return array med objekt
		 */
		public function GetAllInstances($className, $tableName){
			if ($this->m_mysqli == NULL) {
            	throw new Exception("DBConnection, must call Connect before calling Prepare");
            }
			
			$sql = "SELECT * FROM " . $tableName;
			$stmt = $this->Prepare($sql);
			
			if ($stmt === FALSE){
				return false;		
			}
			return $this->RunAndFetchObjects($className, $stmt);
		}
		
		/**
		 * Kör en SQL-fråga som ett preparerad sats och returnerar objekt
		 * Används när man vill ha tillbaka objekt (select) från sin fråga. (typ ExcecuteReader i ADO.NET)
		 * 
		 * @param string $className Namnet på klassen som representerar raderna i tabellen
		 * @param string $sqlQueryToPrepare SQL-frågan med frågetecken (?) vid parametrarna som skall bindas
		 * @param string $bindParamTypeString Sträng innehållandes typen för satsen som skall prepareras. "s" = sträng, "ss" = dubbelsträng osv
		 * @param array $parameterArray Array med parametrar som skall bindas till SQL-frågan.
		 * @return array med objekt.
		 */
		public function RunPreparedSelectQuery($className, $sqlQueryToPrepare, $bindParamTypeString, $parameterArray){
			$stmt = $this->PrepareWithParams($sqlQueryToPrepare, $bindParamTypeString, $parameterArray);
	    	return $this->RunAndFetchObjects($className, $stmt);
		}
		
		
		/**
		 * Kör en SQL-fråga som ett preparerad sats och returnerar true eller false
		 * Används vid SQL-frågor som uppdaterar eller tar bort poster (typ ExcecuteNonQuery i ADO.net)
		 * 
		 * @param string $sqlQueryToPrepare SQL-frågan med frågetecken (?) vid parametrarna som skall bindas
		 * @param string $bindParamTypeString Sträng innehållandes typen för satsen som skall prepareras. "s" = sträng, "ss" = dubbelsträng osv
		 * @param array $parameterArray Array med parameter-referenser som skall bindas
		 * @return array med objekt.
		 */
        public function RunPreparedQuery($sqlQueryToPrepare, $bindParamTypeString, $parameterArray) {
			$stmt = $this->PrepareWithParams($sqlQueryToPrepare, $bindParamTypeString, $parameterArray);	
			
			$ret = $stmt->execute();
			$stmt->close();
			
			return $ret;
        }
		
		
		/**
		 * Tar en preparerad sats och hämtar ut alla objekt ur den
		 * @param string $className Namnet på klassen som representerar varje rad i tabellen
		 * @param mysql_stmt $stmt preparerad SQL-sats.
		 * @return array med objekt
		 */
		public function RunAndFetchObjects($className, mysqli_stmt $stmt){
			$result = $stmt->execute();	


			$ret = array();
			
			// Krashar här..
			$result = $stmt->get_result;

			while ($objekt = $result->fetch_object($className)) {
				
				$ret[$object->pk] = $objekt;
			}
			echo "två";
			
			$stmt->close();
			
			return $ret;
		}
		
		
	}
